Skip to content

Conversation

@seisman
Copy link
Member

@seisman seisman commented Nov 16, 2025

See #4168 (comment) for context.

This PR implements the Position class.

Usage:

>>> import pygmt
>>> fig = pygmt.Figure()
>>> fig.basemap(region=[0, 10, 0, 10], projection="X10c", frame=True)
>>> fig.logo(
...:     position=pygmt.params.Position((3, 3), type="mapcoords", anchor="ML", offset=(0.2, 0.2)),
...:     box=True,
...: )
>>> fig.show()

GMT Documentation: https://docs.generic-mapping-tools.org/dev/reference/features.html#reference-and-anchor-point-specification

Preview: https://pygmt-dev--4212.org.readthedocs.build/en/4212/api/generated/pygmt.params.Position.html


#: Specify the reference point on the plot. The method of defining the reference
#: point is controlled by ``type``, and the exact location is set by ``position``.
location: Sequence[float | str] | AnchorCode
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

position or location?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think location is better as the parameter is already called position and we overall will have the Position class.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The docstring above calls this 'reference point', so how about something like ref or refpt?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe refpoint?

In fact, I'd prefer to make it a positional-only parameter, so it will be used like Position("TL", type="inside"), Position((1, 2)).

In this case, the specific parameter name doesn't really matter, though dataclasses doesn't support positional-only attributes.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I did think of positional-only, but a little tricky with dataclasses as you said. Ok to got with refpoint, but let's see what @yvonnefroehlich thinks.

@seisman seisman changed the title POC: Add the Position class for GMT embellishment placement Add the Position class for GMT embellishment placement Nov 25, 2025
@seisman seisman added the feature Brand new feature label Nov 25, 2025
@seisman seisman added this to the 0.18.0 milestone Nov 25, 2025
@seisman seisman marked this pull request as ready for review November 25, 2025 12:19
@seisman seisman added the needs review This PR has higher priority and needs review. label Nov 25, 2025
@dataclasses.dataclass(repr=False)
class Position(BaseParam):
"""
Class for positioning embellishments on a plot.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment on lines +59 to +63
``type="boxcoords"`` Normalized Coordinates
Use normalized coordinates where (0, 0) is the lower-left corner and (1, 1) is
the upper-right corner of the bounding box of the current plot. Specify
``location`` as (*nx*, *ny*). Useful for positioning relative to plot dimensions
without units.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should be noted that, although the GMT documentation says that nx/ny are values in 0-1, but actually other values are also supported. For example:

gmt begin map
gmt basemap -R0/10/0/5 -JX10c/5c -Baf
gmt logo -Dn-1/-1
gmt end show
Image

Comment on lines +141 to +142
#: If not specified, defaults to ``"inside"`` if ``location`` is a justification
#: code; otherwise defaults to ``"plotcoords"``.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In GMT, the default is "plotcoords", i.e., the code x. Thus, -D1/1 is equivalent to -Dx1/1.

When location is an anchor code, we know that "plotcoords" makes no sense (e.g., -DxTL). type should be either "inside" or "outside". Here, I choose "inside" as the default.

Comment on lines +160 to +162
_valid_anchors = {f"{h}{v}" for v in "TMB" for h in "LCR"} | {
f"{v}{h}" for v in "TMB" for h in "LCR"
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We probably can reuse these codes to validate anchor codes in other wrappers, e.g., the justify parameter in the text module. But I feel we can do it in the future.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature Brand new feature needs review This PR has higher priority and needs review.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants